#include <fstream>

#include "CItem.h"

std::map<std::string, SBaseItem> CItem::Items;
std::map<std::string, SMaterial> CItem::Materials;

bool CItem::isEquipped()
{
	return Equipped;
}

bool CItem::isHeld()
{
	return Held;
}

EEquipSlot CItem::getEquipSlot()
{
	return Items[Name].EquipSlot;
}

float CItem::getWeight()
{
	return Items[Name].Weight * Materials[Material].WeightModifier;
}

std::string CItem::getEquipSlotName(EEquipSlot slot)
{
	switch (slot)
	{
	case EES_HEAD:
		return "Head";

	case EES_NECK:
		return "Neck";

	case EES_BACK:
		return "Back";

	case EES_BODY:
		return "Body";

	case EES_HANDS:
		return "Hands";

	case EES_WIELD:
		return "Wielded";

	case EES_SHIELD:
		return "Shield";

	case EES_RING1:
		return "Ring";

	case EES_RING2:
		return "Ring";

	case EES_LEGS:
		return "Legs";

	case EES_FEET:
		return "Feet";

	default:
		return "Unknown";
	}
}

std::string CItem::getRandomItem()
{
	std::map<std::string, SBaseItem>::iterator item = Items.begin();
	std::advance(item, TCODRandom::getInstance()->getInt(0, Items.size()-1));
	return (*item).first;
}

std::string CItem::getRandomMaterial()
{
	std::map<std::string, SMaterial>::iterator item = Materials.begin();
	std::advance(item, TCODRandom::getInstance()->getInt(0, Materials.size()-1));
	return (*item).first;
}

std::string CItem::getBaseName()
{
	return Name;
}

std::string CItem::getMaterial()
{
	return Material;
}

std::string CItem::getQuality()
{
	return Quality;
}

std::string CItem::getName()
{
	std::string ret = Material;
	ret+= " ";
	ret+= Name;
	return ret;
}

void CItem::createOnGround(std::string name, char shape, pair position)
{
	Name = name;
	Shape = shape;
	Position = position;

	Material = getRandomMaterial();

	Equipped = false;
	Held = false;
}

void CItem::setEquipped(bool equipped)
{
	Equipped = equipped;
}

void CItem::setHeld(bool held)
{
	Held = held;
}

class CItemDataListener : public ITCODParserListener
{
	std::string Current;

	bool parserNewStruct(TCODParser* parser, const TCODParserStruct* str, const char* name)
	{
		if (!name)
			return false;

		Current = name;

		return true;
	}

	bool parserFlag(TCODParser* parser,const char* name)
	{
		return true;
	}

	bool parserProperty(TCODParser* parser, const char* name, TCOD_value_type_t type, TCOD_value_t value)
	{
		if (_strcmpi(name, "type") == 0)
			CItem::Items[Current].Type = value.s;
		else if (_strcmpi(name, "weight") == 0)
			CItem::Items[Current].Weight = value.f;
		else if (_strcmpi(name, "damage") == 0)
			CItem::Items[Current].Damage = value.dice;
		else if (_strcmpi(name, "damageType") == 0)
			CItem::Items[Current].DamageTypes = value.list;
		else if (_strcmpi(name, "equipSlot") == 0)
			CItem::Items[Current].EquipSlot = (EEquipSlot)value.i;

		return true;
	}

	bool parserEndStruct(TCODParser* parser, const TCODParserStruct* str, const char* name)
	{
		return true;
	}

	void error(const char* msg)
	{
		fprintf(stderr, "%s", msg);
		exit(1);
	}

public:
	CItemDataListener() : ITCODParserListener() {}

};

void CItem::loadBaseItems()
{
	TCODParser parser = TCODParser();
	TCODParserStruct* itemStruct = parser.newStructure("item");
	itemStruct->addProperty("type", TCOD_TYPE_STRING, true);
	itemStruct->addProperty("weight", TCOD_TYPE_FLOAT, true);
	itemStruct->addProperty("damage", TCOD_TYPE_DICE, false);
	itemStruct->addListProperty("damageType", TCOD_TYPE_STRING, false);
	itemStruct->addProperty("equipSlot", TCOD_TYPE_INT, false);

	CItemDataListener* listener = new CItemDataListener();
	parser.run("data/items", listener);
	delete listener;
};

class CMaterialDataListener : public ITCODParserListener
{
	std::string Current;

	bool parserNewStruct(TCODParser* parser, const TCODParserStruct* str, const char* name)
	{
		if (!name)
			return false;

		Current = name;

		return true;
	}

	bool parserFlag(TCODParser* parser,const char* name)
	{
		return true;
	}

	bool parserProperty(TCODParser* parser, const char* name, TCOD_value_type_t type, TCOD_value_t value)
	{
		if (_strcmpi(name, "damageModifier") == 0)
			CItem::Materials[Current].DamageModifier = value.f;
		else if (_strcmpi(name, "weightModifier") == 0)
			CItem::Materials[Current].WeightModifier = value.f;

		return true;
	}

	bool parserEndStruct(TCODParser* parser, const TCODParserStruct* str, const char* name)
	{
		return true;
	}

	void error(const char* msg)
	{
		fprintf(stderr, "%s", msg);
		exit(1);
	}

public:
	CMaterialDataListener() : ITCODParserListener() {}

};

void CItem::loadMaterials()
{
	TCODParser parser = TCODParser();

	TCODParserStruct* materialStruct = parser.newStructure("material");
	materialStruct->addProperty("damageModifier", TCOD_TYPE_FLOAT, true);
	materialStruct->addProperty("weightModifier", TCOD_TYPE_FLOAT, true);

	CMaterialDataListener* listener = new CMaterialDataListener();
	parser.run("data/materials", listener);
	delete listener;
}
